<script lang="ts" setup>
import { reactive, ref, shallowRef, onMounted, onActivated } from 'vue'
import { useMap } from '@/hooks/useMap'
import { useActivated } from '@/hooks/useActivated'
import { useRoute } from 'vue-router'
import SearchPlace from '@/components/map/SearchPlace.vue'
import bikeImg from '@/assets/map/bikeLocation/bike.png'
import { queryShortTermBikeLocation, refreshShortTermBikeLocation } from '@/api/bike'
import { bikeLocationDataType, coordinatesType } from '@/api/bike/types/bike'
import { returnLocationType } from '@/types/interface'
import returnPointImg from '@/assets/map/bikeLocation/returnPoint.png'
import activeReturnPointImg from '@/assets/map/bikeLocation/activeReturnPoint.png'
import locationImg from '@/assets/map/bikeLocation/location.png'
import lockImg from '@/assets/map/bikeLocation/lock.png'
import linestatusImg from '@/assets/map/bikeLocation/linestatus.png'
import bikestatusImg from '@/assets/map/bikeLocation/bikestatus.png'
import powerImg from '@/assets/map/bikeLocation/power.png'
import { getToken } from '@/utils/cache/cookies'
import { dayjs, ElMessage } from 'element-plus'
import { LockStatus, OnlineStatus } from '@/types/enum'
import { copyEvent } from '@/utils'
import ControlResite from '@/components/map/ControlResite.vue'
import MeasureTools from '@/components/map/MeasureTools.vue'
defineOptions({
  name: 'TimeBikeLocation'
})
const route = useRoute()
const center = ref<bikeLocationDataType | null>(null)
const watchParams = reactive({
  bikeId: route.query.bikeId,
  storeId: route.query.storeId
})
const isInit = ref<boolean>(false)
const address = ref<any>('')
const updateTime = ref<string>('')
const mapContainer = ref<HTMLDivElement>()
const massmarks = ref<AMap.MassMarks>()
const marker = shallowRef<AMap.Marker>()
const infoWindow = shallowRef<AMap.InfoWindow>()
const bikeInfoWindow = shallowRef<AMap.InfoWindow>()
const circle = ref<AMap.Circle>()
const { map, auto, initAmap, geocoder, placeSearch, getAddress, ruler } = useMap(mapContainer, [
  center.value?.longtitude ?? 0,
  center.value?.latitude ?? 0
])
/** 地图初始化 */
const init = async () => {
  isInit.value = await initAmap()
  updateTime.value = dayjs().format('YYYY-MM-DD HH:mm:ss')
  await getTimeBikeLocation()
}
/** 用于activated */
const handleActivated = async () => {
  await getTimeBikeLocation()
}
/** 生成地图覆盖物 */
const handleCoverInit = async () => {
  if (isInit.value && map.value) {
    map.value.clearMap()
    map.value?.setCenter([center.value?.longtitude ?? 0, center.value?.latitude ?? 0])
    address.value = await getAddress(center.value?.longtitude ?? 0, center.value?.latitude ?? 0)
    marker.value = new AMap.Marker({
      position: new AMap.LngLat(center.value?.longtitude ?? 0, center.value?.latitude ?? 0),
      map: map.value,
      icon: new AMap.Icon({
        image: bikeImg,
        imageSize: new AMap.Size(59, 63),
        size: new AMap.Size(59, 63)
      }),
      offset: new AMap.Pixel(-30, -63)
    })
    marker.value.on('click', handleMarkerClick)
    infoWindow.value = new AMap.InfoWindow({
      autoMove: true,
      offset: new AMap.Pixel(15, 0),
      isCustom: true
    })
    bikeInfoWindow.value = new AMap.InfoWindow({
      autoMove: true,
      offset: new AMap.Pixel(0, -63),
      isCustom: true
    })
    bikeInfoWindow.value?.setContent(
      createBikeContent(
        center.value?.bikeCode ?? '',
        center.value?.powerLevel ?? '0',
        address.value,
        updateTime.value,
        center.value?.lastReturnTime,
        center.value?.plateNumber,
        center.value?.bikeOnlineStatus,
        center.value?.lockStatus,
        center.value?.bikeStatus
      )
    )
    bikeInfoWindow.value?.open(
      map.value!,
      new AMap.LngLat(center.value?.longtitude ?? 0, center.value?.latitude ?? 0)
    )
    if (coordinates.value.length > 0) {
      const polygon = new AMap.Polygon({
        path: coordinates.value,
        strokeColor: '#418DFF',
        strokeOpacity: 1,
        strokeWeight: 3,
        fillColor: '#418DFF',
        fillOpacity: 0.1,
        strokeStyle: 'dashed',
        bubble: true
      })
      map.value?.add(polygon)
    }
    const mapContainer = document.getElementById('map-container')
    mapContainer?.addEventListener('click', handleInfoWindowClick)
    massmarks.value = new AMap.MassMarks(returnLocation.value, {
      style: getStyle(),
      zIndex: 110
    })
    massmarks.value.setMap(map.value)
    massmarks.value?.hide()
    massmarks.value.on('click', handleMassMarksClick)
    circle.value = new AMap.Circle({
      fillColor: '#F3860A',
      fillOpacity: 0.1,
      strokeOpacity: 0
    })
    map.value?.add(circle.value)
    map.value?.setFitView([marker.value])
  }
}
/** 海量点图层样式 */
const getStyle = () => {
  return [
    {
      anchor: new AMap.Pixel(0, 0),
      url: returnPointImg,
      size: new AMap.Size(30, 30)
    },
    {
      anchor: new AMap.Pixel(0, 0),
      url: activeReturnPointImg,
      size: new AMap.Size(30, 30)
    }
  ]
}
/** 给地图添加点击事件 用于刷新 */
const handleInfoWindowClick = (event: any) => {
  if (!event.target.className) return
  // 检查是否点击了 "添加工单" 按钮
  if (event.target.className.includes('button')) {
    refresh()
  }
  if (event.target.className.includes('is-reference')) {
    copyEvent(event.target.dataset.address)
  }
  if (event.target.className.includes('bike-position-infowindow__x')) {
    bikeInfoWindow.value?.close()
  }
}
const returnLocation = ref<returnLocationMapType[]>([])
const bikeLocations = ref<bikeLocationDataType[]>([])
const coordinates = ref<AMap.LngLat[]>([])
/** 请求数据 */
const getTimeBikeLocation = () => {
  return new Promise((resolve, reject) => {
    queryShortTermBikeLocation({
      token: getToken() ?? '',
      bikeId: route.query.bikeId as string,
      storeId: route.query.storeId as string,
      showReturnLocation: 1
    })
      .then((res) => {
        if (res.statusCode === '0') {
          bikeLocations.value = res.data.bikeLocationData
          const centerData = bikeLocations.value[0]
          center.value = centerData
          returnLocation.value = handleReturnLocation(res.data.returnLocation)
          coordinates.value = handleCoordinates(res.data.coordinates)
          handleCoverInit()
          resolve('success')
        } else {
          reject('error')
        }
      })
      .catch((error) => {
        console.error(error)
      })
  })
}
interface returnLocationMapType extends returnLocationType {
  lnglat: [number, number]
}
/** 转换数据用于初始化海量点 */
const handleReturnLocation = (data: returnLocationType[]) => {
  return data.map((location: returnLocationType) => {
    return {
      lnglat: [location.longtitude, location.latitude] as [number, number],
      ...location
    }
  })
}
/** 转换数据用于初始化运营区域 */
const handleCoordinates = (data: coordinatesType[]) => {
  return data.map(
    (location: coordinatesType) => new AMap.LngLat(location.longtitude, location.latitude)
  )
}
/** 格式化bikeOnlineStatus */
const formatBikeOnLineStatus = (bikeOnlineStatus?: OnlineStatus) => {
  switch (bikeOnlineStatus) {
    case OnlineStatus.UnOnLine:
      return '断网'
    case OnlineStatus.OnLine:
      return '联网'
    default:
      return ''
  }
}
/** 格式化bikeOnlineStatus */
const formatLockStatus = (lockStatus?: LockStatus) => {
  switch (lockStatus) {
    case LockStatus.Locked:
      return '上锁'
    case LockStatus.Unlocked:
      return '开锁'
    default:
      return ''
  }
}
/** 海量点信息窗体内容 */
const createBikeContent = (
  bikeCode: string,
  powerLevel: string,
  address: string,
  time: string,
  lastReturnTime?: string,
  carNumber?: string,
  bikeOnlineStatus?: OnlineStatus,
  lockStatus?: LockStatus,
  bikeStatus?: string
) => {
  return `<div class="bike-position-infowindow">
                  <div class="bike-position-infowindow__title">
                    <span class="bike-position-infowindow__bikeId">车辆编号:${bikeCode}</span>
                    <span class="bike-position-infowindow__x">X</span>
                  </div>
                  <div class="bike-position-infowindow__container">
                    <img src="${locationImg}" />
                     <div class="bike-position-infowindow__content">
                     <span class="bike-position-infowindow__address">
                      <span>${address}</span>
                      <span class="is-reference" date-address="${address}">复制</span>
                     </span>
                    <div class="bike-position-infowindow__info">
                      <div class="bike-position-infowindow__carnumber">${carNumber}</div>
                      <div class="bike-position-infowindow__time">
                         <span>位置更新时间:${time}</span>
                         <span>上次还车时间:${lastReturnTime}</span>
                      </div>
                    </div>
                    <div class="bike-position-infowindow__state">
                           <div class="bike-position-infowindow__state-item">
                              <img src="${bikestatusImg}"/>
                              <span>${bikeStatus}</span>
                           </div>
                           <div class="bike-position-infowindow__state-item">
                              <img src="${linestatusImg}"/>
                              <span>${formatBikeOnLineStatus(bikeOnlineStatus)}</span>
                           </div>
                           <div class="bike-position-infowindow__state-item">
                              <img src="${powerImg}"/>
                              <span>${powerLevel}%</span>
                           </div>
                           <div class="bike-position-infowindow__state-item">
                              <img src="${lockImg}"/>
                              <span>${formatLockStatus(lockStatus)}</span>
                           </div>
                    </div>
                  </div>
                  </div>
                  <div class="bike-position-infowindow__button">
                    <button class="button">刷新位置</button>
                  </div>
              </div>`
}
/** 海量点信息窗体内容 */
const createReturnLocationContent = (address: string, returnLocationsId: number, title: string) => {
  return `<div class="return-point-infowindow">
                  <div class="return-point-infowindow__title">
                    <span class="return-point-infowindow__name">${title}</span>
                    <div class="return-point-infowindow__id-content">
                        <span>编号:${returnLocationsId}</span>
                    </div>
                  </div>
                  <div class="return-point-infowindow__address">
                    <span>${address}</span>
                  </div>
              </div>`
}
/** 点击车辆事件 */
const handleMarkerClick = (e: any) => {
  bikeInfoWindow.value?.open(map.value!, e.target.getPosition())
  bikeInfoWindow.value?.setContent(
    createBikeContent(
      center.value?.bikeCode ?? '',
      center.value?.powerLevel ?? '0',
      address.value,
      updateTime.value,
      center.value?.lastReturnTime,
      center.value?.plateNumber,
      center.value?.bikeOnlineStatus,
      center.value?.lockStatus
    )
  )
}
/** 点击海量点的事件 */
const handleMassMarksClick = (e: any) => {
  const index = returnLocation.value.findIndex(
    (item) => item.lnglat[1] === e.data.latitude && item.lnglat[0] === e.data.longtitude
  )
  circle.value?.setCenter(e.data.lnglat)
  circle.value?.setRadius(e.data.radius)
  if (infoWindow.value?.getIsOpen()) {
    infoWindow.value.close()
    returnLocation.value = returnLocation.value.map((item) => {
      return {
        ...item,
        style: 0
      }
    })
    massmarks.value?.setData(returnLocation.value)
    circle.value?.hide()
  } else {
    returnLocation.value = returnLocation.value.map((item, i) => {
      if (index == i) {
        return {
          ...item,
          style: 1
        }
      } else {
        return {
          ...item,
          style: 0
        }
      }
    })
    massmarks.value?.setData(returnLocation.value)
    geocoder.value.getAddress(e.data.lnglat, (status: any, result: any) => {
      if (result.info == 'OK') {
        const name = result.regeocode.aois
          ? result.regeocode.aois[0].name
          : result.regeocode.formattedAddress
        infoWindow.value?.setContent(
          createReturnLocationContent(e.data.address, e.data.returnLocationsId, name)
        )
      } else {
        // 处理获取地址失败的情况
        ElMessage.error('地址解析失败')
        infoWindow.value?.setContent(
          createReturnLocationContent(e.data.address, e.data.returnLocationsId, '')
        )
      }
      infoWindow.value?.open(map.value!, e.data.lnglat)
      circle.value?.show()
      map.value?.setCenter(e.data.lnglat)
    })
  }
}
/** 刷新车辆定位 */
const refresh = async () => {
  const res = await refreshShortTermBikeLocation({
    token: getToken() ?? '',
    bikeId: watchParams.bikeId as string
  })
  if (res.statusCode === '0') {
    ElMessage.success({
      plain: true,
      message: res.data
    })
    await getTimeBikeLocation()
  } else {
    ElMessage.error({
      plain: true,
      message: res.data
    })
  }
}
onMounted(() => {
  init()
})
onActivated(() => {
  watchParams.bikeId = route.query.bikeId
  watchParams.storeId = route.query.storeId
})
/** 处理是否缓存 */
useActivated(
  watchParams,
  { watchParams },
  [
    { key: 'bikeId', path: 'watchParams.bikeId' },
    { key: 'storeId', path: 'watchParams.storeId' }
  ],
  handleActivated,
  []
)

const handleResiteChange = (isOpen: boolean) => {
  if (isOpen) {
    massmarks.value?.show()
  } else {
    massmarks.value?.hide()
  }
}
</script>

<template>
  <div class="xy-map-container">
    <div ref="mapContainer" id="map-container">
      <search-place :auto="auto" :map="map!" :place-search="placeSearch" />
      <control-resite @change="handleResiteChange" />
      <measure-tools :ruler="ruler" class="measure-tools-menu" />
    </div>
  </div>
</template>

<style scoped lang="scss">
:deep(.amap-marker-label) {
  border: none;
  font-size: 12px;
  line-height: 14px;
  color: #333333;
  background: #ffffff;
  border-radius: 5px;
  padding: 8px 10px;
  display: flex;
  flex-direction: column;
  white-space: nowrap;
}
:deep(.bike-position-infowindow) {
  z-index: 999;
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--xy-white-color);
  box-shadow: 0px 3px 6px 1px rgba(0, 0, 0, 0.16);
  border-radius: 8px;
  width: auto;
  .bike-position-infowindow__title {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    padding: 8px 12px 0 12px;
  }
  .bike-position-infowindow__bikeId {
    color: var(--xy-normal-text-color);
    font-size: 16px;
    line-height: 1;
    font-weight: 500;
  }
  .bike-position-infowindow__x {
    color: var(--xy-grey-text-color);
    cursor: pointer;
  }
  .bike-position-infowindow__container {
    padding: 8px 12px 0 12px;
    display: flex;
    img {
      width: 12px;
      height: 12px;
    }
  }
  .bike-position-infowindow__button {
    width: 100%;
    button {
      outline: none;
      border: none;
      cursor: pointer;
      color: var(--xy-primary-color);
      background: var(--xy-white-color);
      width: 100%;
      padding: 10px 0;
    }
  }
  .bike-position-infowindow__content {
    display: flex;
    flex-direction: column;
  }
  .bike-position-infowindow__address {
    font-size: 12px;
    color: var(--xy-normal-text-color);
    line-height: 14px;
  }
  .bike-position-infowindow__info {
    display: flex;
    align-items: center;
    padding: 10px 0;
  }
  .bike-position-infowindow__carnumber {
    background: var(--xy-hover-color);
    border-radius: 4px 4px 4px 4px;
    padding: 10px;
    display: flex;
    align-items: center;
    font-size: 11px;
    color: var(--xy-normal-text-color);
    line-height: 1;
  }
  .bike-position-infowindow__time {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    font-size: 10px;
    color: var(--xy-grey-text-color);
    line-height: 1;
    margin-left: 10px;
    > span:first-child {
      margin-bottom: 8px;
    }
  }
  .bike-position-infowindow__state {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr 1fr;
    grid-template-rows: 1fr;
    margin-top: 7px;
  }
  .bike-position-infowindow__state-item {
    display: flex;
    justify-content: center;
    align-items: center;
    span {
      font-size: 11px;
      color: var(--xy-normal-color);
      margin-left: 5px;
    }
    img {
      width: 14px;
      height: 14px;
    }
  }
}
:deep(.return-point-infowindow) {
  z-index: 999;
  position: relative;
  display: flex;
  flex-direction: column;
  background: #ffffff;
  box-shadow: 0px 3px 6px 1px rgba(0, 0, 0, 0.16);
  border-radius: 5px 5px 5px 5px;
  padding: 10px;
  .return-point-infowindow__title {
    display: flex;
    align-items: center;
    white-space: nowrap;
    .return-point-infowindow__name {
      font-weight: 500;
      font-size: 16px;
      color: rgba(51, 51, 51, 0.99);
      line-height: 22px;
    }
    .return-point-infowindow__id-content {
      line-height: 19px;
      background: rgba(243, 134, 10, 0.1);
      border-radius: 2px 2px 2px 2px;
      padding: 1px 4px;
      display: inline-block;
      text-align: center;
      font-size: 12px;
      color: #f3860a;
      margin-left: 10px;
    }
  }
  .return-point-infowindow__address {
    font-size: 14px;
    color: rgba(102, 102, 102, 0.99);
    line-height: 19px;
    white-space: normal;
  }
}
.measure-tools-menu {
  position: absolute;
  top: 20px;
  right: 70px;
  z-index: 200;
  background-color: #fff;
  padding: 10px 10px;
  box-shadow: 0px 0px 10px 1px rgba(0, 0, 0, 0.1);
  border-radius: 5px 5px 5px 5px;
}
</style>
